package com.example.manage_dzensaas.filter;

import com.example.manage_dzensaas.core.enums.ChannelNoEnum;
import com.example.manage_dzensaas.core.enums.ErrorCodeEnum;
import com.example.manage_dzensaas.core.utils.SignUtils;
import com.example.manage_dzensaas.filter.exception.CustomException;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.AppContext;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.FilterChain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.List;

/**
 * @author wangzhiqi
 * @version 1.0
 * @description: 统一拦截第三方渠道权限
 * @date 2025/1/9 14:07
 */
public class ApiAuthFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(ApiAuthFilter.class);

    @Inject
    private AppContext appContext;

    // 需要验证的接口路径
    private static final List<String> AUTH_PATHS = Arrays.asList(
        "/invoke/*"
    );

    // 时间戳有效期（1分钟）
    private static final long TIMESTAMP_EXPIRE_MILLIS = 1 * 60 * 1000;
    // 时间戳有效期10秒
    private static final long TIMESTAMP_VALIDITY = 5 * 1000;

    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        String path = ctx.path();
        
        // 检查是否需要验证
        if (shouldVerify(path)) {
            // 获取请求参数
            String channelNo = ctx.param("channel_no");
            String timestampStr = ctx.param("timestamp");
            String sign = ctx.param("sign");

            // 验证必传参数
            if (channelNo == null || timestampStr == null || sign == null) {
                throw new CustomException(ErrorCodeEnum.PARAM_ERROR);
            }

            // 验证时间戳
            long timestamp;
            try {
                timestamp = Long.parseLong(timestampStr);
                if (System.currentTimeMillis() - timestamp > TIMESTAMP_VALIDITY) {
                    LOGGER.error("请求已过期，时间戳有效期：{}", TIMESTAMP_VALIDITY / 1000 / 60);
                    throw new CustomException(ErrorCodeEnum.PARAM_ERROR.getCode(), "请求已过期，时间戳有效期");
                }
            } catch (NumberFormatException e) {
                throw new CustomException(ErrorCodeEnum.TIME_ERROR);
            }

            if (ChannelNoEnum.getByCode(channelNo).getSecretKey() == null) {
                throw new CustomException(ErrorCodeEnum.CHANNEL_ERROR);
            }

            // 验证签名
            boolean signValid = SignUtils.verifySign(channelNo, timestamp, sign);
            if (!signValid) {
                String expectedSign = SignUtils.generateSign(channelNo, timestamp, 
                    ChannelNoEnum.getByCode(channelNo).getSecretKey());
                LOGGER.error("签名验证失败，请求签名：{}，预期签名：{}", sign, expectedSign);
                throw new CustomException(ErrorCodeEnum.SIGN_ERROR);
            }
        }
        chain.doFilter(ctx);
    }

    private boolean shouldVerify(String path) {
        // 获取完整路径（包含前缀）
        String fullPath = path.startsWith("/") ? path : "/" + path;
        return AUTH_PATHS.stream().anyMatch(pattern -> pathMatches(pattern, fullPath));
    }

    private boolean pathMatches(String pattern, String path) {
        // 获取contextPath
        String contextPath = appContext.cfg().get("server.contextPath");
        // 处理/manage前缀
        String prefixedPattern = contextPath + pattern;
        
        if (pattern.endsWith("*")) {
            String basePattern = prefixedPattern.substring(0, prefixedPattern.length() - 1);
            return path.startsWith(basePattern);
        }
        return path.equals(prefixedPattern);
    }
}
